#pragma once
#include <thread>
#include <iostream>
#include <vector>
#include <map>
#include <atomic>
#include <queue>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <future>
using namespace std;
/*
构成：
1. 管理者线程 -> 子线程：1个
    控制工作线程的数量：增加或者减少
2. 若干工作线程 -> 子线程：n个
    从任务队列中取任务并处理
    任务队列为空被阻塞
    线程同步(互斥锁)
    当前数量，空闲的线程数量
    最小最大线程数量
3. 任务队列 ->queue
    互斥锁，条件变量
4. 线程池开关 -> bool
*/

class ThreadPool
{
public:
    ThreadPool(int min = 2, int max = thread::hardware_concurrency());
    ~ThreadPool();

    // 添加任务
    void addTask(function<void(void)> task);

    template <typename F, typename... Args>
    auto addTask(F &&f, Args &&...args) -> future<typename result_of<F(Args...)>::type>
    {
        // 1. package_task
        using returnType = typename result_of<F(Args...)>::type;
        auto mytask = make_shared<packaged_task<returnType()>>(
            bind(forward<F>(f), forward<Args>(args)...));
        // 2. 得到future
        future<returnType> res = mytask->get_future();
        // 3. 添加到任务队列
        m_queueMutex.lock();
        m_tasks.emplace([mytask]()
                        { (*mytask)(); });
        m_queueMutex.unlock();
        m_condition.notify_one();
        return res;
    }

private:
    void manager(void);
    void worker(void);

private:
    thread *m_manager;
    map<thread::id, thread> m_workers;
    vector<thread::id> m_ids; // 存储已经退出了任务函数的线程ID
    atomic<int> m_minThread;
    atomic<int> m_maxThread;
    atomic<int> m_curThread;
    atomic<int> m_idleThread; // 空闲线程
    atomic<int> m_exitThread;
    atomic<bool> m_stop;
    queue<function<void(void)>> m_tasks;
    mutex m_queueMutex;
    mutex m_idsMutex;
    condition_variable m_condition;
};